/**
 * Copyright 2015 ABSir's Studio
 * 
 * All right reserved
 *
 * Create on 2015年6月10日 下午7:28:42
 */
package com.absir.appserv.system.converter;

import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;

import com.absir.appserv.system.adapter.SocketAdapter;
import com.absir.appserv.system.adapter.SocketAdapter.CallbackAdapte;
import com.absir.appserv.system.helper.HelperDatabind;
import com.absir.core.base.Environment;
import com.absir.core.kernel.KernelCharset;
import com.absir.core.kernel.KernelClass;
import com.absir.core.util.UtilFuture;
import com.absir.server.socket.InputSocket.InputSocketAtt;

/**
 * @author absir
 *
 */
@SuppressWarnings("unchecked")
public abstract class CallbackJson<T> implements CallbackAdapte {

	/** TYPE_VARIABLE */
	public static final TypeVariable<?> TYPE_VARIABLE = CallbackJson.class.getTypeParameters()[0];

	/** beanType */
	protected Type beanType;

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.absir.appserv.system.adapter.SocketAdapter.CallbackAdapte#doWith
	 * (com.absir.appserv.system.adapter.SocketAdapter, byte[])
	 */
	@Override
	public void doWith(SocketAdapter adapter, byte[] buffer) {

		if (buffer == null) {
			doWithBean(null, false, null, adapter);
			return;
		}

		if (buffer.length == 0) {
			doWithBean(null, true, null, adapter);
			return;
		}

		boolean ok = (buffer[0] & InputSocketAtt.ERROR_FLAG) == 0;
		if (beanType == null) {
			beanType = KernelClass.type(getClass(), TYPE_VARIABLE);
			if (beanType == null) {
				beanType = CallbackJson.class;
			}
		}

		T bean = null;
		if (ok && beanType != CallbackJson.class) {
			int length = buffer.length;
			if (length > 5) {
				try {
					if (beanType == byte[].class) {
						bean = (T) buffer;

					} else if (beanType == String.class) {
						bean = (T) new String(buffer, 5, length - 5, KernelCharset.UTF8);

					} else {
						bean = (T) HelperDatabind.OBJECT_MAPPER.readValue(buffer, 5, length - 5,
								HelperDatabind.OBJECT_MAPPER.constructType(beanType));
					}

				} catch (Exception e) {
					if (Environment.getEnvironment() == Environment.DEVELOP) {
						e.printStackTrace();
					}
				}
			}
		}

		doWithBean(bean, ok, buffer, adapter);
	}

	/**
	 * @param bean
	 * @param ok
	 * @param buffer
	 * @param adapter
	 */
	public abstract void doWithBean(T bean, boolean ok, byte[] buffer, SocketAdapter adapter);

	/**
	 * @author absir
	 *
	 * @param <T>
	 */
	public static class CallbackJsonFuture<T> extends CallbackJson<T> {

		/** future */
		private UtilFuture<T> future = new UtilFuture<T>();

		/**
		 * @return the future
		 */
		public UtilFuture<T> getFuture() {
			return future;
		}

		/**
		 * @return
		 */
		public T getFutureBean() {
			return future.getBean();
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * com.absir.appserv.system.converter.BodyMsgPack.CallbackMessagePack
		 * #doWithBean(java.lang.Object, boolean, byte[],
		 * com.absir.appserv.system.adapter.SocketAdapter)
		 */
		@Override
		public void doWithBean(T bean, boolean ok, byte[] buffer, SocketAdapter adapter) {
			future.setBean(bean);
		}
	}
}
